package com.ithinks.flow.common.utils;

import lombok.extern.flogger.Flogger;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

/**
 * @Description 通过接口取到Spring容器中实例化的bean
 * @ClassName SpringContextHolder
 * @Author MR.LI
 * @date 2020.11.20 16:25
 */
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(SpringContextHolder.class);

    private static ApplicationContext applicationContext = null;

    /**
     * 取得存储在静态变量中的ApplicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext(){

        assertContextInjected();
        return applicationContext;
    }

    /**
     * 实现ApplicationContextAware接口，注入Context到静态变量中
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;
    }

    private static void assertContextInjected() {

        Validate.validState(applicationContext!=null,"applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
    }


    /**
     * 实现DisposableBean接口，在context关闭时清理静态变量
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {

        SpringContextHolder.clearHolder();

    }

    /**
     * 容器关闭，清除上下文中的bean
     */
    public static void clearHolder(){
        if(LOGGER.isDebugEnabled())
        {
            LOGGER.debug("清除SpringcontextHolder中的ApplicationContext:{}",applicationContext);
        }
        applicationContext = null;
    }

    /**
     * 通过bean名称获取bean对象
     * @param beanName
     * @param <T>
     * @return
     */
    public static <T> T getBean(String beanName)
    {
        assertContextInjected();
        return (T)applicationContext.getBean(beanName);
    }

    /**
     * 根据类的泛型获取bean
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz)
    {
        assertContextInjected();
        return applicationContext.getBean(clazz);
    }


}
